import { createElement } from "react";
import { modifySchema, ErrorBoundary, deepClone } from '@inbiz/utils';
import { properCase } from './utils'
const groupContext = require['context']('../../components', true, /\.(\/[a-zA-Z0-9]+){1,2}\/index.ts(x?)$/i)


// 获取分组数据
const getGroupData = () => {
    const groupData = []; const paths = groupContext.keys()
    paths.filter(item => item.match(/\//g).length === 2).forEach(path => {
        const pathArr = path.split('/').slice(1, -1);
        const data = JSON.parse(JSON.stringify(groupContext(path).default));
        data.key = pathArr[0];
        groupData.push(data)
    });
    const classifySort = groupData.map(item => item.classifySort?.map(sItem => `./${item.key}/${sItem}/index.ts`) || []).flat();
    paths.sort((pre, next) => {
        const preIndex = classifySort.indexOf(pre),
            nextIndex = classifySort.indexOf(next);
        if (preIndex != -1 && nextIndex != -1) {
            return preIndex - nextIndex;
        }
        if (preIndex == -1 || nextIndex == -1) {
            return preIndex == -1 ? 1 : -1;
        }
        return 1;
    }).filter(item => item.match(/\//g).length === 3).forEach(path => {
        const pathArr = path.split('/').slice(1, -1);
        const data = deepClone(groupContext(path).default);
        const item = groupData.find(item => item.key == pathArr[0]);
        if (!item.data) {
            item.data = {}
        };
        if (!item.data[pathArr[1]]) {
            item.data[pathArr[1]] = data;
            data.components = []
            data.sort = data.sort.map?.(item => item.toLowerCase())
        }
    });
    groupData.sort((pre, next) => {
        return (pre.sort - next.sort) || 0
    })
    return groupData as {
        icon: string,
        key: string,
        hidden?: boolean
        appBlackList: string[],
        flowBlackList: string[]
        classifySort: string[],
        data: Record<string, {
            name: string,
            sort?: string[],
            components: { Behavior: { name: string }[] }[]
        }>
    }[];
}

export const getComponent = (componentContext, platform: 'web' | 'wap') => {
    const groupData = getGroupData()
    const componentContextKeys = componentContext.keys() as string[];

    const keys = componentContextKeys.filter((path: string, _index: number, arr: string[]) => {
        if (path.includes(`/${platform}/`)) {
            if (path.includes('/designer/')) {
                return true;
            } else {
                const designerPath = path.replace('/preview/', '/designer/');
                if (arr.includes(designerPath)) {
                    return false;
                } else {
                    return true;
                }
            }
        } else {
            return false;
        }
    }).map((item) => {
        if (item.includes('/preview/')) {
            const index = item.indexOf(`/${platform}/`);
            const schemaPath = item.slice(0, index).replace('/preview', '/designer') + '/schema.ts';
            return [
                item,
                componentContextKeys.find((item) => item.includes(schemaPath)),
            ] as const;
        } else {
            return [item] as const;
        }
    });

    return new Promise((resolve, reject) => {
        const components: Record<string, any> = {};
        const arrComponents = keys.map(async ([path, schemaPath]) => {
            const pathArr = path.split('/').slice(1, -1).filter(item => item != 'SyncComponents');
            const key = pathArr[2];
            const component = (await componentContext(path)).default;
            if (schemaPath && component) {
                const schemaContext = await componentContext(schemaPath);
                const { Behavior, Resource } = (schemaContext || {}) as {
                    Behavior: any;
                    Resource: any;
                };
                component.Behavior = Behavior;
                component.Resource = Resource;
                const render = component.render;
                component.render = (props: any, ref: any) => {
                    return createElement(ErrorBoundary, null, render(props, ref));
                };
            }
            if (component) {
                modifySchema(component, platform);
                components[properCase(key)] = component;
                groupDataAddComponent(groupData, pathArr, component, key)
            }
        });
        Promise.all(arrComponents).then(() => {
            sortGroupComponent(groupData)
            resolve({
                component: components,
                classCompent: groupData.filter(item => !item.hidden)
            });
        }).catch((e) => {
            reject(e);
        });
    });
}

function groupDataAddComponent(groupData, pathArr: string[], component, key: string) {
    const { data: group } = groupData.find(item => item.key == pathArr[0]);
    group[pathArr[1]].components.push(component)
}

function sortGroupComponent(groupData: ReturnType<typeof getGroupData>) {
    groupData.forEach(item => {
        Object.values(item.data).forEach(ele => {
            if (ele.sort?.length) {
                ele.components = ele.components.sort((pre, next) => {
                    const preIndex = ele.sort.indexOf(pre.Behavior[0].name.toLowerCase()),
                        nextIndex = ele.sort.indexOf(next.Behavior[0].name.toLowerCase());
                    if (preIndex != -1 && nextIndex != -1) {
                        return preIndex - nextIndex;
                    }
                    if (preIndex == -1 || nextIndex == -1) {
                        return preIndex == -1 ? 1 : -1;
                    }
                })
            }
        })
    })
}